package com.mspbots.core.ticketai.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.mspbots.core.AbstractBaseServiceImpl;
import com.mspbots.core.ticketai.mapper.RuleStatusPointsMapper;
import com.mspbots.core.ticketai.model.RuleStatusPoints;
import com.mspbots.core.ticketai.model.TicketRule;
import com.mspbots.core.ticketai.service.RuleStatusPointsService;
import com.mspbots.core.ticketai.service.TicketRuleService;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author Jay.Yang
 */

@Service
public class RuleStatusPointsServiceImpl extends AbstractBaseServiceImpl<RuleStatusPointsMapper, RuleStatusPoints>
        implements RuleStatusPointsService {

    private final TicketRuleService ticketRuleService;

    public RuleStatusPointsServiceImpl(TicketRuleService ticketRuleService) {
        this.ticketRuleService = ticketRuleService;
    }

    @Override
    public Map<String, TicketRule> saveBatchAll(List<RuleStatusPoints> statusPointsList) {
        TicketRule ticketRule = new TicketRule(statusPointsList.get(0).getTenantId(), "STATUS_POINTS_GRADE_RULE");
        List<TicketRule> allStatusPoints = ticketRuleService.getAllBoardRulesByName(ticketRule);
        statusPointsList.forEach(s -> {
            List<TicketRule> filterList;
            if (StringUtils.isEmpty(s.getBoardNameKeyword()) || StringUtils.isEmpty(s.getBoardRelation())) {
                filterList = new ArrayList<>();
            } else if ("include".equalsIgnoreCase(s.getBoardRelation())) {
                if ("*".equals(s.getBoardNameKeyword())) {
                    filterList = allStatusPoints;
                } else {
                    filterList = allStatusPoints.stream().filter(a -> a.getBoardName().toLowerCase().contains(s.getBoardNameKeyword())).collect(Collectors.toList());
                }
            } else {
                if ("*".equals(s.getBoardNameKeyword())) {
                    filterList = new ArrayList<>();
                } else {
                    filterList = allStatusPoints.stream().filter(a -> !a.getBoardName().toLowerCase().contains(s.getBoardNameKeyword())).collect(Collectors.toList());
                }
            }
            if (!CollectionUtils.isEmpty(filterList)
                    && !StringUtils.isEmpty(s.getStatusName())
                    && !StringUtils.isEmpty(s.getStatusRelation())) {
                filterList.forEach(f -> {
                    Iterator<JsonNode> nodeJson = f.getParams().elements();
                    while (nodeJson.hasNext()) {
                        ObjectNode objectNode = (ObjectNode) nodeJson.next();
                        if (StringUtils.isEmpty(objectNode.get("name"))) {
                            continue;
                        }
                        switch (s.getStatusRelation().toLowerCase()) {
                            case "include":
                                if ("*".equals(s.getStatusName()) || objectNode.get("name").asText().toLowerCase().contains(s.getStatusName().toLowerCase())) {
                                    objectNode.putPOJO("points", s.getPoints());
                                }
                                break;
                            case "exclude":
                                if (!"*".equals(s.getStatusName()) && !objectNode.get("name").asText().toLowerCase().contains(s.getStatusName().toLowerCase())) {
                                    objectNode.putPOJO("points", s.getPoints());
                                }
                                break;
                            case "equal":
                                if ("*".equals(s.getStatusName()) || objectNode.get("name").asText().equalsIgnoreCase(s.getStatusName())) {
                                    objectNode.putPOJO("points", s.getPoints());
                                }
                                break;
                            case "unequal":
                                if (!"*".equals(s.getStatusName()) && !objectNode.get("name").asText().equalsIgnoreCase(s.getStatusName())) {
                                    objectNode.putPOJO("points", s.getPoints());
                                }
                                break;
                            default:
                                break;
                        }
                    }
                });
                ticketRuleService.saveOrUpdateBatch(filterList);
            }
        });
        super.saveOrUpdateBatch(statusPointsList);
        return allStatusPoints.stream().collect(Collectors.toMap(TicketRule::getBoardName, Function.identity(), (key1, key2) -> key2));
    }

    @Override
    public Map<String, TicketRule> getAllStatusPoints(Long tenantId) {
        TicketRule ticketRule = new TicketRule(tenantId, "STATUS_POINTS_GRADE_RULE");
        List<TicketRule> allStatusPoints = ticketRuleService.getAllBoardRulesByName(ticketRule);
        return allStatusPoints.stream().collect(Collectors.toMap(TicketRule::getBoardName, Function.identity(), (key1, key2) -> key2));
    }

    @Override
    public List<RuleStatusPoints> selectData(Long tenantId) {
        List<RuleStatusPoints> list = super.list(Wrappers.<RuleStatusPoints>lambdaQuery()
                .eq(RuleStatusPoints::getTenantId, tenantId));
        if (CollectionUtils.isEmpty(list)) {
            return initData(tenantId);
        }
        return list;
    }

    @Override
    public List<RuleStatusPoints> initData(Long tenantId) {
        super.remove(Wrappers.<RuleStatusPoints>lambdaQuery()
                .eq(RuleStatusPoints::getTenantId, tenantId));

        List<RuleStatusPoints> initList = super.list(Wrappers.<RuleStatusPoints>lambdaQuery()
                .eq(RuleStatusPoints::getTenantId, -1));
        if (CollectionUtils.isEmpty(initList)) {
            initList = initDbData();
        }
        initList.parallelStream().forEach(r -> {
            r.setId(null);
            r.setTenantId(tenantId);
        });
        super.saveBatch(initList);
        return initList;
    }

    private List<RuleStatusPoints> initDbData() {
        RuleStatusPoints statusPoints = new RuleStatusPoints();
        statusPoints.setTenantId(-1L);
        statusPoints.setBoardRelation("include");
        statusPoints.setStatusRelation("include");
        try {
            String statusDefaultPoints = "[{\"time\": 10, \"point\": 10}, {\"time\": 20, \"point\": 10}, {\"time\": 30, \"point\": 10}, {\"time\": 60, \"point\": 10}, {\"time\": 120, \"point\": 10}, {\"time\": 240, \"point\": 10}, {\"time\": 480, \"point\": 10}, {\"time\": 720, \"point\": 10}, {\"time\": 1440, \"point\": 10}, {\"time\": 2880, \"point\": 10}, {\"time\": 4320, \"point\": 10}, {\"time\": 7200, \"point\": 10}, {\"time\": 11520, \"point\": 10}, {\"time\": 20160, \"point\": 10}, {\"time\": 43200, \"point\": 10}]";
            statusPoints.setPoints(objectMapper.readTree(statusDefaultPoints));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        super.save(statusPoints);
        return List.of(statusPoints);
    }

}
